package ace.tool.generate.code.impl.service;

import ace.cmp.json.api.JsonService;
import ace.cmp.json.api.JsonUtils;
import ace.cmp.json.jackson.JacksonService;
import ace.tool.generate.code.impl.manager.ApiProjectManager;
import ace.tool.generate.code.impl.manager.CoreProjectManager;
import ace.tool.generate.code.impl.manager.ModuleProjectManager;
import ace.tool.generate.code.impl.manager.SdkProjectManager;
import ace.tool.generate.code.impl.resolver.scheme.GenerateInputResolver;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.GenerateContext;
import ace.tool.generate.code.impl.service.model.input.GenerateInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelInput;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import lombok.Builder;
import lombok.SneakyThrows;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.util.ResourceUtils;

/**
 * @author caspar
 * @date 2023/11/20 15:12
 */
@Builder
public final class GeneratorProjectSchemaService {

  private final JsonService jsonService = new JacksonService();

  public GeneratorProjectSchemaService() {
    JsonUtils.setJsonService(new JacksonService());
  }

  public void generate(GenerateInput input) {

    this.loadModelFiles(input);

    GenerateContext context = new GenerateInputResolver(input).resolve();

    this.deleteModuleProject(input, context);

    this.generateModuleProject(context);

    this.generateApiProject(context);

    this.generateSdkProject(context);

    this.generateCoreProject(context);
  }

  private void loadModelFiles(GenerateInput input) {
    if (CollectionUtils.isEmpty(input.getModelFileDirPaths())) {
      return;
    }
    input
        .getModelFileDirPaths()

        .forEach(modelFileDirPath -> {
          List<GenerateModelInput> generateModelInput = this.getModelInputFromFileDirPath(
              modelFileDirPath);
          input.getModels().addAll(generateModelInput);
        });
  }

  @SneakyThrows
  private List<GenerateModelInput> getModelInputFromFileDirPath(String modelFileDirPath) {
    List<GenerateModelInput> result = new ArrayList<>();
    File dir = ResourceUtils.getFile(modelFileDirPath);
    for (File file : dir.listFiles()) {
      String fileContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
      List<GenerateModelInput> input = jsonService.toList(fileContent, GenerateModelInput.class);
      result.addAll(input);
    }
    return result;
  }

  @SneakyThrows
  public void generate(String resourcePath) {
    File file = ResourceUtils.getFile(resourcePath);
    String fileContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
    GenerateInput input = jsonService.toObject(fileContent, GenerateInput.class);
    this.generate(input);
  }

  @SneakyThrows
  private void deleteModuleProject(GenerateInput input, GenerateContext context) {
    if (!input.getDeleteModuleProjectRootDir()) {
      return;
    }
    File file = new File(context.getModuleProject().getInfo().getRootDir());
    if (!file.exists()) {
      return;
    }
    FileUtils.forceDelete(file);
  }

  private void generateCoreProject(GenerateContext context) {
    new CoreProjectManager(context).generate();
  }

  private void generateSdkProject(GenerateContext context) {
    new SdkProjectManager(context).generate();
  }

  private void generateApiProject(GenerateContext context) {
    new ApiProjectManager(context).generate();
  }

  private void generateModuleProject(GenerateContext context) {
    new ModuleProjectManager(context).generate();
  }
}
